package dev.ece.util;

import dev.ece.util.lib.Matrix4f;
import dev.ece.util.lib.Vector3f;
import dev.ece.util.lib.Vector4f;

/**
 * 几何运算工具
 * @author 潜行的虚影
 *
 */
public class GeoUtils {

	/**
	 * 射线与三角形交点
	 * @param o 射线起点
	 * @param dir 射线方向
	 * @param v0 三角形顶点0
	 * @param v1 三角形顶点1
	 * @param v2 三角形顶点2
	 * @param result 如果返回true，则此参数内容设置为交点坐标
	 * @return 是否有交点
	 */
	public static boolean intersectTriangle(
			Vector3f o, Vector3f dir, Vector3f v0, Vector3f v1, Vector3f v2, Vector3f result) {
		// E1
	    Vector3f E1 = new Vector3f();
	    E1.splus(v0, v1);
	    // E2
	    Vector3f E2 = new Vector3f();
	    E2.splus(v0, v2);
	    
	    Vector3f P = dir.cross(E2);
	    
	    // determinant
	    float det = E1.dot(P);
	    
	    // keep det > 0, modify T accordingly
	    Vector3f T = new Vector3f();
	    if( det >0 ) {
	        T.splus(v0, o);
	    } else {
	        T.splus(o, v0);
	        det = -det;
	    }
	    // If determinant is near zero, ray lies in plane of triangle
	    if( det < 0.0001f )
	        return false;
	 
	    // Calculate u and make sure u <= 1
	    float u = T.dot(P);
	    if(u < 0.0f || u > det )
	        return false;
	    // Q
	    Vector3f Q = T.cross(E1);
	 
	    // Calculate v and make sure u + v <= 1
	    float v = dir.dot(Q);
	    if(v < 0.0f || u + v > det )
	        return false;
	    
	    if(result != null) {
	    	// Calculate t, scale parameters, ray intersects triangle
		    //float t = E2.dot(Q);
	    	float fInvDet = 1.0f / det;
		    //t *= fInvDet;
		    u *= fInvDet;
		    v *= fInvDet;
	    	float puv = (1 - u - v); 
		    result.setX(puv * v0.getX() + u * v1.getX() + v * v2.getX());
		    result.setY(puv * v0.getY() + u * v1.getY() + v * v2.getY());
		    result.setZ(puv * v0.getZ() + u * v1.getZ() + v * v2.getZ());
	    }
	    //计算交点坐标
		return true;
	}
	
	public static Vector3f invert(Matrix4f[] invertMatrix, Vector3f vertex, Vector4f bones, Vector4f weights) {
		Vector3f result = new Vector3f();
		if(invertMatrix != null) {
			Vector3f temp = null;
			boolean isNotWeight = true;
			for(int i=0; i<4; i++) {
				if(bones.getVector()[i] > -1 && weights.getVector()[i] > 0) {
					temp = new Vector3f(vertex);
					invertMatrix[(int) bones.getVector()[i]].transform(temp);
					temp.mul(weights.getVector()[i]);
					result.add(temp);
					isNotWeight = false;
				}
			}
			if(isNotWeight) {
				return vertex;
			}
		} else {
			return vertex;
		}
		return result;
	}
	
}
